package com.shareppy.normanhttp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

import android.content.Context;

import com.shareppy.normanhttp.tasks.SppyBgTask;
import com.shareppy.normanhttp.tasks.TaskException;

public abstract class AbstractHttpRequest extends
		SppyBgTask<HttpRequestParams, Object> {

	public static final String HEADER_CONTENT_TYPE = "Content-Type";
	public static final String HEADER_SHAREPPY_TIMESTAMP = "Shareppy-Timestamp";
	public static final String HEADER_USER_AGENT = "User-Agent";
	public static final String HEADER_AUTHORIZATION = "Authorization";
	public static final String HEADER_COOKIE = "Cookie";
	public static final String HEADER_SET_COOKIE = "Set-Cookie";

	protected String service;
	protected int activityId;
	protected String taskTitle;

	public AbstractHttpRequest(Context context) {
		super(context);
	}

	public AbstractHttpRequest(Context context, String service) {
		this(context, service, DEFAULT_TASK);
	}

	public AbstractHttpRequest(Context context, String service, int activityId) {
		this(context, service, activityId, null);
	}

	public AbstractHttpRequest(Context context, String service, int activityId,
			String taskTitle) {
		super(context);
		this.service = service;
		this.activityId = activityId;
		this.taskTitle = taskTitle;
	}

	protected boolean manageCookie() {
		return true;
	}

	@Override
	protected  Object run(HttpRequestParams params) {
		return perform(params);
	}

	protected Object perform(HttpRequestParams params) {
		int statusCode = 0;
		try {
			HttpClient client = new DefaultHttpClient();
			String serviceUrl = HttpTaskConfig.serverUrl + service;
			HttpPost post = new HttpPost(serviceUrl);
			addHeaders(post, params);
			addParameters(params, post);
			HttpResponse response = client.execute(post);
			readCookie(response);
			processResponse(response);
			statusCode = response.getStatusLine().getStatusCode();
			if (statusCode == 200) {
				return readResponse(response);
			}
			return new TaskException(statusCode, readResponse(response));
		} catch (Exception e) {
			e.printStackTrace();
			return new TaskException(statusCode, e.getMessage());
		}
	}

	private void addHeaders(HttpPost post, HttpRequestParams params) {
		addCustomHeaders(post, params);
		post.addHeader(HEADER_CONTENT_TYPE, getContentType());
		post.addHeader(HEADER_USER_AGENT, getUserAgent());
		if (manageCookie()) {
			if (HttpTaskConfig.cookie != null) {
				post.addHeader(HEADER_COOKIE, HttpTaskConfig.cookie);
			}
		}
	}

	protected final String getUserAgent() {
		return "shareppy-android";
	}

	protected String getContentType() {
		return "application/x-www-form-urlencoded";
	}

	private void readCookie(HttpResponse response) {
		if (manageCookie()) {
			if (HttpTaskConfig.cookie == null) {
				HttpTaskConfig.cookie = extractCookie(response
						.getHeaders(HEADER_SET_COOKIE));
			}
		}
	}

	protected void processResponse(HttpResponse response) {
		return;
	}

	private void addParameters(HttpRequestParams params, HttpPost post)
			throws UnsupportedEncodingException {
		if (params != null && !params.isEmpty()) {
			addCustomParams(params);
			List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(
					params.size());
			Set<String> keySet = params.keys();
			for (String key : keySet) {
				nameValuePairs.add(new BasicNameValuePair(key, (String) params
						.get(key)));
			}
			post.setEntity(new UrlEncodedFormEntity(nameValuePairs, HTTP.UTF_8));
		}
	}

	protected void addCustomParams(HttpRequestParams params) {
		return;
	}

	protected void addCustomHeaders(HttpPost post, HttpRequestParams params) {
		return;
	}

	protected static String readResponse(HttpResponse response)
			throws IOException {
		BufferedReader rd = new BufferedReader(new InputStreamReader(response
				.getEntity().getContent()));
		StringBuilder responsestr = new StringBuilder();
		while (true) {
			String line = rd.readLine();
			if (line == null) {
				break;
			}
			responsestr.append(line).append("\n");
		}
		return responsestr.toString();
	}

	protected String extractCookie(Header[] cookies) {
		for (Header cookie : cookies) {
			final int ix = cookie.getValue().indexOf("JSESSIONID=");
			if (ix != -1) {
				final int lix = cookie.getValue().indexOf(';', ix);
				if (lix != -1) {
					return cookie.getValue().substring(ix, lix);
				}
				return cookie.getValue().substring(ix);
			}
		}
		return null;
	}

	public void setActivityId(int activityId) {
		this.activityId = activityId;
	}

	public int getActivityId() {
		return activityId;
	}

	public String getTaskTitle() {
		return taskTitle;
	}

	public void setTaskTitle(String taskTitle) {
		this.taskTitle = taskTitle;
	}

	public abstract <T extends AbstractHttpRequest> T getClone();
}